var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
// 数据结构bucket
var bucket = new WeakMap();
var acctiveFnStack = [];
var Iterate_Key = Symbol();
var Type;
(function (Type) {
    Type[Type["Add"] = 0] = "Add";
    Type[Type["Update"] = 1] = "Update";
})(Type || (Type = {}));
var activeEffectFn = null;
function track(target, key) {
    if (!activeEffectFn)
        return;
    // 需要将target对应的key添加到桶中
    var map = bucket.get(target);
    if (!map) {
        bucket.set(target, (map = new Map()));
    }
    var set = map.get(key);
    if (!set) {
        map.set(key, (set = new Set()));
    }
    set.add(activeEffectFn);
    activeEffectFn.deps.push(set);
}
function trigger(target, key, type) {
    var map = bucket.get(target);
    if (!map)
        return;
    var effectFns = map.get(key);
    var efectsToRun = new Set();
    var iterate_effectfns = map.get(Iterate_Key);
    effectFns &&
        effectFns.forEach(function (effect) {
            efectsToRun.add(effect);
        });
    if (type === Type.Add) {
        iterate_effectfns &&
            iterate_effectfns.forEach(function (effect) {
                efectsToRun.add(effect);
            });
    }
    efectsToRun.forEach(function (effect) {
        if (effect.options && effect.options.schedule) {
            effect.options.schedule(effect);
            return;
        }
        if (effect && effect !== activeEffectFn)
            effect();
    });
}
function cleanUp(wrapper) {
    var deps = wrapper.deps;
    for (var i = 0; i < deps.length; i++) {
        var set = deps[i];
        set.delete(wrapper);
    }
    wrapper.deps.length = 0;
}
function effect(fn, options) {
    var wrapper = function () {
        cleanUp(wrapper);
        acctiveFnStack.push(wrapper);
        activeEffectFn = wrapper;
        var value = fn();
        acctiveFnStack.pop();
        activeEffectFn = acctiveFnStack[acctiveFnStack.length - 1];
        return value;
    };
    // 在触发之前清除掉后续没有绑定的属性
    wrapper.deps = [];
    wrapper.options = options;
    if (options && options.lazy) {
        return wrapper;
    }
    else {
        return wrapper();
    }
}
var isFlush = false;
var jobQueue = new Set();
var p = Promise.resolve();
function jobRun() {
    if (isFlush)
        return;
    isFlush = true;
    p.then(function () {
        jobQueue.forEach(function (fn) {
            fn();
        });
    }).finally(function () {
        isFlush = false;
    });
}
// set的时候触发trigger
var handle = {
    get: function (target, key, receiver) {
        // 当get的时候触发track
        track(target, key);
        return Reflect.get(target, key, receiver);
    },
    set: function (target, key, newValue, receiver) {
        var type = Object.prototype.hasOwnProperty.call(target, key)
            ? Type.Update
            : Type.Add;
        Reflect.set(target, key, newValue, receiver);
        trigger(target, key, type);
        return true;
    },
    has: function (target, key) {
        track(target, key);
        return Reflect.has(target, key);
    },
    ownKeys: function (target) {
        track(target, Iterate_Key);
        return Reflect.ownKeys(target);
    },
};
var obj = {
    name: "zs",
    age: 14,
    ok: true,
    num: 1,
    get bar() {
        return this.age;
    },
};
// proxy代理对象
var proxyObj = new Proxy(obj, handle);
effect(function () {
    for (var key in proxyObj) {
        console.log(key);
    }
});
proxyObj.ccc = "update";
// computed的实现
function computed(getter) {
    var isCache = false;
    var effectFn = effect(getter, {
        schedule: function (effect) {
            effectFn = effect;
            isCache = false;
            trigger(obj, "value", Type.Update);
        },
        lazy: true,
    });
    var value = effectFn();
    var obj = {
        get value() {
            if (!isCache) {
                value = effectFn();
                isCache = true;
                track(obj, "value");
            }
            return value;
        },
    };
    return obj;
}
//watch的实现
/**
 * 1 watcher传入一个函数或者属性或属性字符串  一个回调
 * 2 如果函数直接放到effect中
 *    如果是
 *
 */
function travese(obj, map) {
    if (map === void 0) { map = new Map(); }
    var target = {};
    map.set(obj, obj);
    for (var key in obj) {
        if (typeof obj[key] === "object" && !map.has(obj[key])) {
            target[key] = travese(obj[key], map);
        }
        else {
            target[key] = obj[key];
        }
    }
    return __assign({}, target);
}
function watch(source, cb, options) {
    var getter;
    var oldValue;
    var newValue;
    var cleanUp;
    var overwriteExpire;
    overwriteExpire = function (fn) {
        cleanUp = fn;
    };
    if (typeof source === "function") {
        getter = function () { return source(); };
    }
    else if (typeof source === "object") {
        getter = function () { return travese(source); };
    }
    else {
        return;
    }
    function job() {
        if (cleanUp) {
            cleanUp();
        }
        newValue = curEffectFn();
        cb(oldValue, newValue, overwriteExpire);
        oldValue = newValue;
    }
    var curEffectFn = effect(getter, {
        schedule: function (effectFn) {
            curEffectFn = effectFn;
            job();
        },
        lazy: true,
    });
    if (options === null || options === void 0 ? void 0 : options.immidate) {
        job();
    }
    else {
        curEffectFn();
    }
}
